#ifndef TB_BASE_H__
#define TB_BASE_H__

#include <vector>

#include <boost/checked_delete.hpp>
#include <boost/preprocessor.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/and.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/system/error_code.hpp>
#include <tbb/scalable_allocator.h>

#include "tbcore/config.hpp"
#include "tbcore/base/basic_types.hpp"
#include "tbcore/gtest/gtest/include/gtest/gtest_prod.h"

#if defined(TB_CXX_PREFER_STD_LIB)
#include <memory>
#include <tuple>
#include <functional>
#include <xtr1common>
#include <atomic>
#define TB_STATIC_ASSERT static_assert
TB_NAMESPACE_BEGIN
using _STD shared_ptr;
using _STD weak_ptr;
using _STD tuple;
using _STD make_tuple;
using _STD function;
using _STD make_shared;
using _STD make_unique;
using _STD bind;
using _STD static_pointer_cast;
using _STD const_pointer_cast;
using _STD enable_if;
using _STD get;
using _STD enable_shared_from_this;
using namespace std::placeholders;
using _STD atomic;
using _STD atomic_bool;
using _STD atomic;
using _STD atomic_char;
using _STD atomic_schar;
using _STD atomic_uchar;
using _STD atomic_short;
using _STD atomic_ushort;
using _STD atomic_int;
using _STD atomic_uint;
using _STD atomic_long;
using _STD atomic_ulong;
using _STD atomic_llong;
using _STD atomic_ullong;
using _STD memory_order_relaxed;
using _STD memory_order_consume;
using _STD memory_order_acquire;
using _STD memory_order_release;
using _STD memory_order_acq_rel;
using _STD memory_order_seq_cst;
TB_NAMESPACE_END
#else
#include <boost/smart_ptr.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/function.hpp>
#include <boost/make_shared.hpp>
#include <boost/make_unique.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/core/enable_if.hpp>
#include <boost/atomic.hpp>
#define TB_STATIC_ASSERT(a, b) BOOST_STATIC_ASSERT(a)
TB_NAMESPACE_BEGIN
using ::boost::shared_ptr;
using ::boost::weak_ptr;
using ::boost::tuple;
using ::boost::make_tuple;
using ::boost::function;
using ::boost::make_shared;
using ::boost::make_unique;
using ::boost::bind;
using ::boost::static_pointer_cast;
using ::boost::const_pointer_cast;
using ::boost::enable_if;
using ::boost::enable_if_c;
using ::boost::get;
using ::boost::enable_shared_from_this;
using ::boost::atomics;
using ::boost::memory_order_relaxed;
using ::boost::memory_order_consume;
using ::boost::memory_order_acquire;
using ::boost::memory_order_release;
using ::boost::memory_order_acq_rel;
using ::boost::memory_order_seq_cst;
TB_NAMESPACE_END
#endif 

#if !defined(TB_NO_CXX_TYPE_TRAIT)
# include <type_traits>
# define TB_TYPE_TRAITS_NAMESPACE ::std
#else
# include <boost/type_traits.hpp>
# define TB_TYPE_TRAITS_NAMESPACE ::boost
#endif 

TB_NAMESPACE_BEGIN

struct null_deleter {
  //! Function object result type
  typedef void result_type;

  null_deleter(bool del = false) : del_(del) {}
  /*!
  * Does nothing
  */
  template< typename T >
  void operator() (T*) const NOEXCEPT {}

private:
  bool del_;
};

typedef shared_ptr<void> VoidPtr;
typedef weak_ptr<void> VoidWPtr;

using TB_TYPE_TRAITS_NAMESPACE::false_type;
using TB_TYPE_TRAITS_NAMESPACE::is_arithmetic;
using TB_TYPE_TRAITS_NAMESPACE::is_base_of;
using TB_TYPE_TRAITS_NAMESPACE::is_polymorphic;
using TB_TYPE_TRAITS_NAMESPACE::is_class;
using TB_TYPE_TRAITS_NAMESPACE::is_array;
using TB_TYPE_TRAITS_NAMESPACE::is_enum;
using TB_TYPE_TRAITS_NAMESPACE::is_floating_point;
using TB_TYPE_TRAITS_NAMESPACE::is_integral;
using TB_TYPE_TRAITS_NAMESPACE::is_object;
using TB_TYPE_TRAITS_NAMESPACE::is_pod;
using TB_TYPE_TRAITS_NAMESPACE::is_reference;
using TB_TYPE_TRAITS_NAMESPACE::is_const;
using TB_TYPE_TRAITS_NAMESPACE::is_same;
using TB_TYPE_TRAITS_NAMESPACE::is_signed;
using TB_TYPE_TRAITS_NAMESPACE::is_unsigned;
using TB_TYPE_TRAITS_NAMESPACE::is_pointer;
using TB_TYPE_TRAITS_NAMESPACE::is_void;
using TB_TYPE_TRAITS_NAMESPACE::is_member_function_pointer;
using TB_TYPE_TRAITS_NAMESPACE::is_member_object_pointer;
using TB_TYPE_TRAITS_NAMESPACE::is_member_pointer;
using TB_TYPE_TRAITS_NAMESPACE::is_convertible;
using TB_TYPE_TRAITS_NAMESPACE::decay;
using TB_TYPE_TRAITS_NAMESPACE::make_signed;
using TB_TYPE_TRAITS_NAMESPACE::make_unsigned;
using TB_TYPE_TRAITS_NAMESPACE::remove_const;
using TB_TYPE_TRAITS_NAMESPACE::add_lvalue_reference;
using TB_TYPE_TRAITS_NAMESPACE::add_rvalue_reference;
using TB_TYPE_TRAITS_NAMESPACE::remove_reference;
using TB_TYPE_TRAITS_NAMESPACE::remove_cv;
using TB_TYPE_TRAITS_NAMESPACE::remove_pointer;
using TB_TYPE_TRAITS_NAMESPACE::true_type;
using TB_TYPE_TRAITS_NAMESPACE::is_abstract;
using TB_TYPE_TRAITS_NAMESPACE::is_copy_constructible;

TB_NAMESPACE_END

#define TB_DECLARE_CLASS_PTR_IMPL(cls) \
typedef TB_NAMESPACE::shared_ptr<class cls> cls##Ptr; \
typedef TB_NAMESPACE::weak_ptr<class cls> cls##WPtr

#define TB_DECLARE_CLASS_PTR(cls) TB_DECLARE_CLASS_PTR_IMPL(cls)

#define TB_DECLARE_STRUCT_PTR_IMPL(cls) \
typedef TB_NAMESPACE::shared_ptr<struct cls> cls##Ptr; \
typedef TB_NAMESPACE::weak_ptr<struct cls> cls##WPtr

#define TB_DECLARE_STRUCT_PTR(cls) TB_DECLARE_STRUCT_PTR_IMPL(cls)

#define TB_TESTBIT(x, b) \
  (((x) & (b)) != 0)
#define TB_SETBIT(x, b) \
  x = ((x) | (b))
#define TB_CLRBIT(x, b) \
  x = ((x) & (~(b)))

#define TB_MAKE_UINT64(a, b) ((((uint64)a) << 32) + b)

TB_NAMESPACE_BEGIN
template <typename T>
void ScalableDelete(T* p) {
  p->~T();
  scalable_free(p);
}
template <typename T>
struct ScalableDeleter {
  void operator()(void* p) const {
    ScalableDelete(static_cast<T*>(p));
  }
};
TB_NAMESPACE_END

#define TB_OPTIMIZED_NEW(value_type) \
::new ((scalable_malloc(sizeof(value_type)))) value_type

#define TB_OPTIMIZED_NEW_ARG(value_type, ...) \
::new ((scalable_malloc(sizeof(value_type)))) value_type(__VA_ARGS__)

#define TB_OPTIMIZED_DELETE(p) \
  TB_NAMESPACE::ScalableDelete(p)

#define TB_OPTIMIZED_MALLOC(size) \
  scalable_malloc(size)

#define TB_OPTIMIZED_CALLOC(elemsize, size) \
  scalable_calloc(elemsize, size)

#define TB_OPTIMIZED_REALLOC(p, size) \
  scalable_realloc(p, size)

#define TB_OPTIMIZED_FREE(p) \
  scalable_free(p)

#define TB_DISABLE_COPY_AND_ASSIGN(cls) \
 private:\
  cls(const cls& rhs);\
  cls& operator=(const cls& rhs);

template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];

#if defined(TB_COMPILER_MSVC)
template <typename T, size_t N>
char (&ArraySizeHelper(const T (&arr)[N]))[N];
#endif

#define TB_ARRAYSIZE(arr) (sizeof(ArraySizeHelper(arr)))

#define TB_ARRAYSIZE_UNSAFE(arr) \
  ((sizeof(arr) / sizeof(*(arr))) / \
  static_cast<size_t>(!(sizeof(arr) % sizeof(*(arr)))))

#define TB_IGNORE_EXCEPTION_TRY(x) \
	try { x; } catch (const std::exception& ex) { LDEBUG() << ex.what(); }

#define TB_SHARED_FROM_THIS(type) \
  TB_NAMESPACE::static_pointer_cast<type>(shared_from_this())

#endif // TB_BASE_H__
